/*
 * Copyright 2011-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0.
 * See `LICENSE` in the project root for license information.
 */

package me.ijleex.mgmt.system.auth.autoconfigure;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.List;

import org.jose4j.jwk.Use;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;

/**
 * 授权属性配置.
 *
 * @author liym
 * @since 2020-08-09 18:22 新建
 */
@ConfigurationProperties(prefix = "auth")
@Configuration
public class AuthProperties {

    private List<String> postAllowPatterns;

    private final Jwt jwt = new Jwt();

    public List<String> getPostAllowPatterns() {
        return postAllowPatterns;
    }

    public void setPostAllowPatterns(List<String> postAllowPatterns) {
        this.postAllowPatterns = postAllowPatterns;
    }

    public Jwt getJwt() {
        return jwt;
    }

    /**
     * @see org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties.Jwt
     */
    public static class Jwt {

        private int size = 2048;
        private String use = Use.SIGNATURE;
        private String keyId = "b064d64b09924181b773e6d69fb0a662";
        /**
         * 在开发应用的时候启用 JWT，使用 RS256、ES256 更加安全
         */
        private String algorithm = "RS256";

        private Resource publicKeyLocation;
        private Resource privateKeyLocation;

        private Duration expireTime;

        public int getSize() {
            return size;
        }

        public void setSize(int size) {
            this.size = size;
        }

        public String getUse() {
            return use;
        }

        public void setUse(String use) {
            this.use = use;
        }

        public String getKeyId() {
            return keyId;
        }

        public void setKeyId(String keyId) {
            this.keyId = keyId;
        }

        public String getAlgorithm() {
            return algorithm;
        }

        public void setAlgorithm(String algorithm) {
            this.algorithm = algorithm;
        }

        public void setPublicKeyLocation(Resource publicKeyLocation) {
            this.publicKeyLocation = publicKeyLocation;
        }

        public void setPrivateKeyLocation(Resource privateKeyLocation) {
            this.privateKeyLocation = privateKeyLocation;
        }

        public Duration getExpireTime() {
            return expireTime;
        }

        public void setExpireTime(Duration expireTime) {
            this.expireTime = expireTime;
        }

        public String readPublicKey() {
            String key = "auth.jwt.public-key-location";
            Assert.notNull(this.publicKeyLocation, "PublicKeyLocation must not be null");
            if (!this.publicKeyLocation.exists()) {
                throw new InvalidConfigurationPropertyValueException(key, this.publicKeyLocation,
                        "Public key location does not exist");
            }
            try (InputStream in = this.publicKeyLocation.getInputStream()) {
                return StreamUtils.copyToString(in, StandardCharsets.UTF_8);
            } catch (IOException e) {
                throw new InvalidConfigurationPropertyValueException(key, this.publicKeyLocation,
                        "Read public key failed");
            }
        }

        public String readPrivateKey() {
            String key = "auth.jwt.private-key-location";
            Assert.notNull(this.privateKeyLocation, "PrivateKeyLocation must not be null");
            if (!this.privateKeyLocation.exists()) {
                throw new InvalidConfigurationPropertyValueException(key, this.privateKeyLocation,
                        "Private key location does not exist");
            }
            try (InputStream in = this.privateKeyLocation.getInputStream()) {
                return StreamUtils.copyToString(in, StandardCharsets.UTF_8);
            } catch (IOException e) {
                throw new InvalidConfigurationPropertyValueException(key, this.privateKeyLocation,
                        "Read private key failed");
            }
        }

    }

}
